from datetime import date, datetime
import re
from typing import Union

import numpy as np
import pandas as pd


def is_valid_datetime(datetime_string):
    formats = ['%Y-%m-%d', '%Y-%m', '%Y-%m-%d %H:%M:%S']  # 可接受的日期时间格式列表

    for fmt in formats:
        try:
            datetime.strptime(datetime_string, fmt)  # 尝试使用格式进行转换
            return True
        except ValueError:
            pass

    return False


def tran_to_intArray(s: str) -> Union[list[int], None]:
    if str is None or len(s) == 0:
        return None
    try:
        int_list = [int(x) for x in s.replace(" ", "").replace("'", "").replace('"', "").strip("[]").split(",")]
        return int_list
    except ValueError:
        return None
    except Exception as e:
        return None


def sortByMaybeNumStr(sortBy):
    def _sortByNumStr(row):
        if isinstance(row[sortBy], int) or isinstance(row[sortBy], float):
            return row[sortBy]
        if not isinstance(row[sortBy], str):
            return 0
        sortStr = re.sub(r"[^\d-]", "", row[sortBy], count=0, flags=0)
        if len(sortStr) == 0:
            return 0
        return float(sortStr)

    return _sortByNumStr


def check_xlsx(fileName):
    return '.' in fileName and fileName.rsplit('.', 1)[1] in ['xlsx']


def int_formatter(df: pd.DataFrame, cols: list[str]) -> pd.DataFrame:
    for col in cols:
        if col in df.columns:
            df[col] = pd.to_numeric(df[col], errors='coerce').astype(pd.Int64Dtype()).apply((lambda x: format(x, ",") if x is not None and not pd.isna(x) else ""))
    return df


def float_round_formatter(df: pd.DataFrame, cols: list[str], ro=2) -> pd.DataFrame:
    for col in cols:
        if col in df.columns:
            df[col] = pd.to_numeric(df[col], errors='coerce').apply((lambda x: format(x, f",.{ro}f") if x is not None and not pd.isna(x) else ""))
    return df


def precentage_round_formatter(df: pd.DataFrame, cols: list[str], ro=2) -> pd.DataFrame:
    for col in cols:
        if col in df.columns:
            df[col] = (pd.to_numeric(df[col], errors='coerce') * 100).apply((lambda x: format(x, f",.{ro}f")+"%" if x is not None and not pd.isna(x) else ""))
    return df


def thousandth_round_formatter(df: pd.DataFrame, cols: list[str], ro=2) -> pd.DataFrame:
    for col in cols:
        if col in df.columns:
            df[col] = (pd.to_numeric(df[col], errors='coerce') * 1000).apply((lambda x: format(x, f",.{ro}f")+"‰" if x is not None and not pd.isna(x) else ""))
    return df


def datetime_formatter(df: pd.DataFrame, cols: list[str], format_str=None) -> pd.DataFrame:
    datetime_formatter_str = "%Y-%m-%d %H:%M:%S"
    date_formatter_str = "%Y-%m-%d"
    if format_str is not None and isinstance(format_str, str):
        for col in cols:
            if col in df.columns:
                df[col] = df[col].apply(lambda x: x.strftime(format_str) if type(x) in [datetime, date] else x)
    else:
        for col in cols:
            if col in df.columns:
                df[col] = df[col].apply(lambda x: x.strftime(datetime_formatter_str) if isinstance(x, datetime) else (x.strftime(date_formatter_str)) if isinstance(x, date) else x)
    return df


def clean_NaN_in_listDict(data: list[dict]) -> list[dict]:
    for d in data:
        for key, value in d.items():
            if value in [np.inf, -np.inf]:
                d[key] = 'Infinity'
            elif pd.isnull(value) or value is "nan":
                d[key] = 'NaN'
            elif isinstance(value, datetime):
                d[key] = value.strftime('%Y-%m-%d %H:%M:%S')
            elif isinstance(value, date):
                d[key] = value.strftime('%Y-%m-%d')
            elif isinstance(key, str) and (key.endswith("_rate") or key.endswith("_growth")) and isinstance(value, float):
                d[key] = (format(value * 100, ".2f") + "%")
            elif isinstance(value, int) or isinstance(value, float):
                d[key] = format(value, ",")
    return data
